package com.authine.cloudpivot.ext.util;

import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @program: gomro
 * @description:
 * @author: wlw
 * @create: 2021-10-09 12:06
 **/
public class RedisUtil {

    private static StringRedisTemplate redisTemplate = ApplicationContextUtils.getBean(StringRedisTemplate.class);

    /**
     * 加锁，无阻塞
     * @param key 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @param timeOut 超时时间
     * @return 是否获取成功
     */
    public static Boolean lock(String key, long expireTime,long timeOut,String requestId) {

        Long start = System.currentTimeMillis();
        //在一定时间内获取锁，超时则返回错误
        for (;;){
            //Set命令返回OK，则证明获取锁成功
            Boolean ret = redisTemplate.opsForValue().setIfAbsent( key, requestId, expireTime, TimeUnit.SECONDS);
            if (ret) {
                return true;
            }
            //否则循环等待，在timeout时间内仍未获取到锁，则获取失败
            long end = System.currentTimeMillis() - start;
            if (end >= timeOut){
                return false;
            }
        }
    }

    /**
     * 解锁
     * @param key
     * @param requestId
     * @return
     */
    public static Boolean unlock(String key, String requestId) {

        //获取值 + 对比 + 删除 必须是原子操作  lua脚本解锁
        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                "then " +
                "   return  redis.call('del', KEYS[1])" +
                "else " +
                "   return 0 " +
                "end";
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(luaScript, Long.class), Collections.singletonList(key), requestId);
    return Optional.ofNullable(result).orElse(0L) == 1;
    }


}
